package mycoffee.order.activity;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.text.Format;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.gson.Gson;
import com.mobile.android.connectionmanager.*;
import mycoffee.order.R;
import mycoffee.order.adapter.AreaAdapter;
import mycoffee.order.adapter.FoodAdapter;
import mycoffee.order.adapter.InvoiceAdapter;
import mycoffee.order.adapter.InvoiceDetailAdapter;
import mycoffee.order.adapter.OrderAdapter;
import mycoffee.order.adapter.TableAdapter;
import mycoffee.order.decoder.CacheManager;
import mycoffee.order.decoder.DecoderListener;
import mycoffee.order.dialog.DiscountDialog;
import mycoffee.order.dialog.PaymentDialog;
import mycoffee.order.jsonhandler.AreaJsonHandler;
import mycoffee.order.jsonhandler.BaseJsonHandler.OnCompleted;
import mycoffee.order.jsonhandler.CategoryJsonHandler;
import mycoffee.order.jsonhandler.FoodsJsonHandler;
import mycoffee.order.jsonhandler.SubCategoryJsonHandler;
import mycoffee.order.jsonhandler.TableJsonHandler;
import mycoffee.order.model.Area;
import mycoffee.order.model.Category;
import mycoffee.order.model.Constants;
import mycoffee.order.model.Discount;
import mycoffee.order.model.Food;
import mycoffee.order.model.Order;
import mycoffee.order.model.OrdersDetail;
import mycoffee.order.model.SubCategory;
import mycoffee.order.model.Table;
import mycoffee.order.task.AreasTask;
import mycoffee.order.task.FoodsTask;
import mycoffee.order.task.IDataEventHandler;
import mycoffee.order.task.OrderEditTask;
import mycoffee.order.task.OrderQueryTask;
import mycoffee.order.task.UploadInvoiceTask;
import mycoffee.order.utils.CommonUtils;
import mycoffee.order.utils.LogUtils;
import mycoffee.order.utils.PrefUtils;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;

import com.citizen.port.android.BluetoothPort;
import com.citizen.request.android.RequestHandler;
import com.print.AlertView;
import com.print.ESCPSample2;
import com.print.PrinterSettingDialog;

/**
 * 
 * @author Tuong
 * 
 */
public class MainActivity extends BaseActivity implements DecoderListener,
		OnScrollListener, OnClickListener{
	/** list of foods that is displaying. */
	private ArrayList<Food> mCurrentFoods = new ArrayList<Food>();
	/** list of categories. */
	private ArrayList<Category> mCategories = new ArrayList<Category>();
	/** display list of foods. */
	private GridView mGvFoods;
	/** display list of subcategories. */
	private LinearLayout mLlSubCategories;
	private ArrayList<View> mSubCategoryItems = new ArrayList<View>();
	private LinearLayout mLlCategories;
	private FoodAdapter mFoodAdapter;
	private AreaAdapter mAreaAdapter;
	private TableAdapter mTableAdapter;
	private AreaAdapter m1stAreaAdapter;
	private TableAdapter m1stTableAdapter;
	private AreaAdapter m2ndAreaAdapter;
	private TableAdapter m2ndTableAdapter;
	private ArrayList<Order> mInvoices;
	private ArrayList<Order> mAllInvoices;
	public ArrayList<Order> mOrders;
	/** position of table that is selected. */
	private int mCurrentTableIndex = Constants.INVALID_VALUE;
	private int m1stCurrentTableIndex = Constants.INVALID_VALUE;
	private int m2ndCurrentTableIndex = Constants.INVALID_VALUE;
	/** position of area that is selected. */
	private int mCurrentAreaIndex = Constants.INVALID_VALUE;
	private int m1stCurrentAreaIndex = Constants.INVALID_VALUE;
	private int m2ndCurrentAreaIndex = Constants.INVALID_VALUE;
	/** position of category that is selected. */
	private int mCurrentCategoryIndex = Constants.INVALID_VALUE;
	private int mCurrentInvoiceFilterIndex = Constants.INVALID_VALUE;
	/** position of subcategory that is selected. */
	private int mCurrentSubCategoryIndex = Constants.INVALID_VALUE;
	/** used to decode icon of food. */
	private CacheManager mCacheManager;
	private ListView mLvOrderDetails;
	private ListView mLv1stOrderDetails;
	private ListView mLv2ndOrderDetails;
	private ListView mLvInvoiceDetails;
	private ListView mLvInvoices;
	private OrderAdapter mOrderAdapter;
	private InvoiceDetailAdapter m1stOrderAdapter;
	private InvoiceDetailAdapter m2ndOrderAdapter;
	private InvoiceAdapter mInvoiceAdapter;
	private InvoiceDetailAdapter mInvoiceDetailAdapter;
	private TextView mTvTotalMoney;
	private TextView mTvTotalMoneyOfInvoices;
	private TextView mTvInvoiceDetailsTitle;
	private TextView mTvInvoiceDetailsCreator;
	private TextView mTvInvoiceDetailsTable;
	private TextView mTvInvoiceDetailsDate;
	private TextView mTvInvoiceDetailsTotal;
	private double mTotalMoneyOfInvoices;

	// Order Footer
	private View mOrderFooterView;
	private TextView mTvOrderFooterTotalTitle;
	private TextView mTvOrderFooterTotalValue;
	private TextView mTvOrderFooterDiscountTitle;
	private TextView mTvOrderFooterDiscountValue;
	private TextView mTvOrderFooterDiscountTotalMoney;
	private TextView mTvOrderFooterDiscountName;
	private LinearLayout mLlOrderFooterTotal;
	private LinearLayout mLlOrderFooterDiscount;

	// Invoice Footer
	private View mInvoiceFooterView;
	private TextView mTvInvoiceFooterTotalTitle;
	private TextView mTvInvoiceFooterTotalValue;
	private TextView mTvInvoiceFooterDiscountTitle;
	private TextView mTvInvoiceFooterDiscountValue;
	private TextView mTvInvoiceFooterDiscountTotalMoney;
	private TextView mTvInvoiceFooterDiscountName;
	private LinearLayout mLlInvoiceFooterTotal;
	private LinearLayout mLlInvoiceFooterDiscount;

	private Button mBtLanguage;
	private Button mBtPayment;
	private Button mBtDiscount;
	private Button mBtPrintOrder;

	private Button mBtOrder;
	private Button mBtInvoice;
	private Button mBtTableJoinSplit;
	private TextView mTvArea;
	private TextView mTvTable;
	private TextView mTvListOrders;
	private TextView mTvListInvoices;
	private TextView mTv1stArea;
	private TextView mTv1stTable;
	private TextView mTv1stListOrders;
	private TextView mTv2ndArea;
	private TextView mTv2ndTable;
	private TextView mTv2ndListOrders;

	private ArrayList<Table> mTables;
	private ArrayList<Area> mAreas;
	private ArrayList<Order> mOrderTempFromDatabase = null;
	private ArrayList<Order> mInvoiceFromDatabase = null;
	private boolean mIsNeedSavingDataBeforeFinish = true;

	private final static String PASS_WORD = "123456";
	private static final String TAG = "BluetoothConnectMenu";
	// Intent request codes
	// private static final int REQUEST_CONNECT_DEVICE = 1;
	private static final int REQUEST_ENABLE_BT = 2;
	public static final String BT_DEVICE_ADDRESS = "DefaultDevice";
	private String currentDeviceAddress;
	ArrayAdapter<String> adapter;
	private BluetoothAdapter mBluetoothAdapter;
	private Vector<BluetoothDevice> remoteDevices;
	private Thread hThread;
	private static boolean connected;
	// BT
	private BluetoothPort bp;
	private ProgressDialog dialog;

	//
	/** position of order that is selected to diplay [add] and [remove] button. */
	private int mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
	private int mCurrentInvoiceSelectedIndex = Constants.INVALID_VALUE;

	private AtomicInteger mFinishLoadData = new AtomicInteger(0);
	private AtomicInteger mFinishSynzServer = new AtomicInteger(0);
	private AtomicInteger mFinishSaveData = new AtomicInteger(0);

	private DiscountDialog mDiscountDialog;
	private PaymentDialog mPaymentDialog;

	private static final int FINISH_SAVE_ORDERS = 1;
	private static final int FINISH_SAVE_INVOICES = 2;

	private static final int FINISH_LOAD_AREAS = 1;
	private static final int FINISH_LOAD_FOODS = 2;
	private static final int FINISH_LOAD_ORDERS = 4;
	private static final int FINISH_LOAD_INVOICES = 8;
	private TabHost tabHost;

	private static final int SYNZ_CATEGORY_TABLES = 1;
	private static final int SYNZ_SUBCATEGORY_TABLES = 2;
	private static final int SYNZ_FOOD_TABLES = 4;
	private static final int SYNZ_AREA_TABLES = 8;
	private static final int SYNZ_TABLE_TABLES = 16;
	
	boolean isSynz = false;
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.main);

		MyCoffeeApplication.startApp(getApplicationContext());
		//
		isSynz = false;
		Button btSynz = (Button) this.findViewById(R.id.bt_synz);
		btSynz.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				isSynz = true;
				mFinishLoadData.set(FINISH_LOAD_INVOICES);
				mFinishSynzServer.set(0);
				synzDataFromServer();
			}
		});
		//synz
		synzDataFromServer();
		// Setting
		bluetoothSetup();
		// Restore printer config
		SharedPreferences settings = getSharedPreferences(BT_DEVICE_ADDRESS, 0);
		String deviceAddress = settings.getString("deviceAddress", "");
		if (deviceAddress.equals("") == false) {
			try {
				btConn(mBluetoothAdapter.getRemoteDevice(deviceAddress));
			} catch (Exception e) {
				// Bluetooth Address Format [OO:OO:OO:OO:OO:OO]
				Log.e(TAG, e.getMessage(), e);
				AlertView.showError(e.getMessage(), MainActivity.this);
				return;
			}
		}
	}

	@Override
	protected void onResume() {
		super.onResume();
		if (mCurrentFoods != null && mCurrentFoods.size() > 0) {
			startDecoder();
		}
		// if (mGvFoods != null) {
		// mGvFoods.setVisibility(View.VISIBLE);
		// }
		if (mFoodAdapter != null) {
			mFoodAdapter.notifyDataSetChanged();
		}

	}

	@Override
	protected void onPause() {
		super.onPause();
		// stop decoder.
		if (mCacheManager != null) {
			mCacheManager.setStop(true);
			mCacheManager.removeAllBitmapsFromCache();
		}

		// if (mGvFoods != null) {
		// mGvFoods.setVisibility(View.GONE);
		// }
	}

	@Override
	public void finish() {
		// save data before finish app.
		// insert to order temp
		if (mIsNeedSavingDataBeforeFinish) {
			showProgress(R.string.saving);
			OrderEditTask task = new OrderEditTask(getApplicationContext(),
					new IDataEventHandler<Boolean>() {

						@Override
						public void onNotify(Boolean data) {
							synchronized ( mFinishSaveData ) {
								mFinishSaveData.set(mFinishSaveData.get()
									| FINISH_SAVE_ORDERS);
								if (isFinishSaving()) {
									mIsNeedSavingDataBeforeFinish = false;
									dismissProgress();
									finish();
								}
							}
						}
					}, true, mOrders) {

			};
			task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

			OrderEditTask task2 = new OrderEditTask(getApplicationContext(),
					new IDataEventHandler<Boolean>() {

						@Override
						public void onNotify(Boolean data) {
							synchronized ( mFinishSaveData ) {
								mFinishSaveData.set(mFinishSaveData.get()
										| FINISH_SAVE_INVOICES);
								if (isFinishSaving()) {
									mIsNeedSavingDataBeforeFinish = false;
									dismissProgress();
									finish();
								}
							}
						}
					}, false, mAllInvoices) {

			};
			task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
		} else {
			super.finish();
		}

	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		// release memory
		if (mCacheManager != null) {
			mCacheManager.releaseMemory();
		}
		if (getDiscountDialog() != null) {
			getDiscountDialog().dismiss();
			setDiscountDialog(null);
		}

		if (mPaymentDialog != null) {
			mPaymentDialog.dismiss();
			mPaymentDialog = null;
		}
		MyCoffeeApplication.finishApp();
		try {
			bp.disconnect();
		} catch (IOException e) {
			Log.e(TAG, e.getMessage(), e);
		}
		if ((hThread != null) && (hThread.isAlive())) {
			hThread.interrupt();
			hThread = null;
		}
	}

	private void synzDataFromServer() {
		try {
			if ( !ConnectionManager.isNetworkAvailable(this) ) {
				this.dumyData();
				return;
			}
			HttpRequest	request;
			String action = getResources().getString(R.string.action_get);
			String url;
			request = new HttpRequest();
			request.setContext(this);
			//category
			CategoryJsonHandler cateHandler = new CategoryJsonHandler();
			if ( isSynz || cateHandler.isSynz() ) {
				url = getResources().getString(R.string.url_category);
				url = url + action;

				cateHandler.SetOnCompleted(new OnCompleted() {
					
					@Override
					public void Finish() {
						// TODO Auto-generated method stub
						synchronized ( mFinishSynzServer ) {
							mFinishSynzServer.set ( mFinishSynzServer.get()
									| SYNZ_CATEGORY_TABLES );
							if ( isFinishSynz() ) {
								dismissProgress();
								dumyData();
							}
						}
					}

					@Override
					public void Failed() {
						// TODO Auto-generated method stub
						dismissProgress();
						dumyData();
					}
				});

				request.setHandler( cateHandler );
				request.setUrl(url);
				request.sendRequest();
			} else
			{
				synchronized ( mFinishSynzServer ) {
					mFinishSynzServer.set ( mFinishSynzServer.get()
							| SYNZ_CATEGORY_TABLES );
				}
			}
			
			//sub category
			SubCategoryJsonHandler subCateHandler = new SubCategoryJsonHandler();
			if ( isSynz || subCateHandler.isSynz() ) {
				request = new HttpRequest();
				request.setContext(this);
				url = getResources().getString(R.string.url_subcategory) + action;
				subCateHandler.SetOnCompleted(new OnCompleted() {
					
					@Override
					public void Finish() {
						// TODO Auto-generated method stub
						synchronized ( mFinishSynzServer ) {
							mFinishSynzServer.set ( mFinishSynzServer.get()
									| SYNZ_SUBCATEGORY_TABLES );
							if ( isFinishSynz() ) {
								dismissProgress();
								dumyData();
							}
						}
					}

					@Override
					public void Failed() {
						// TODO Auto-generated method stub
						dismissProgress();
						dumyData();
					}
				});
				request.setHandler( subCateHandler );
				request.setUrl(url);
				request.sendRequest();
			} else {
				synchronized ( mFinishSynzServer ) {
					mFinishSynzServer.set ( mFinishSynzServer.get()
							| SYNZ_SUBCATEGORY_TABLES );
				}
			}

			//Foods
			FoodsJsonHandler foodHandler = new FoodsJsonHandler(this);
			if ( isSynz || foodHandler.isSynz() ) {
				request = new HttpRequest();
				request.setContext(this);
				url = getResources().getString(R.string.url_food) + action;
				foodHandler.SetOnCompleted(new OnCompleted() {
					
					@Override
					public void Finish() {
						// TODO Auto-generated method stub
						synchronized ( mFinishSynzServer ) {
							mFinishSynzServer.set ( mFinishSynzServer.get()
									| SYNZ_FOOD_TABLES );
							if ( isFinishSynz() ) {
								dismissProgress();
								dumyData();
							}
						}
					}

					@Override
					public void Failed() {
						// TODO Auto-generated method stub
						dismissProgress();
						dumyData();
					}
				});
				request.setHandler( foodHandler );
				request.setUrl(url);
				request.sendRequest();
			} else {
				synchronized ( mFinishSynzServer ) {
					mFinishSynzServer.set ( mFinishSynzServer.get()
							| SYNZ_FOOD_TABLES );
				}
			}
			
			//Areas
			AreaJsonHandler areaHandler = new AreaJsonHandler();
			if ( isSynz || areaHandler.isSynz() ) {
				request = new HttpRequest();
				request.setContext(this);
				url = getResources().getString(R.string.url_area) + action;
				areaHandler.SetOnCompleted(new OnCompleted() {
					
					@Override
					public void Finish() {
						// TODO Auto-generated method stub
						synchronized ( mFinishSynzServer ) {
							mFinishSynzServer.set ( mFinishSynzServer.get()
									| SYNZ_AREA_TABLES );
							if ( isFinishSynz() ) {
								dismissProgress();
								dumyData();
							}
						}
					}

					@Override
					public void Failed() {
						// TODO Auto-generated method stub
						dismissProgress();
						dumyData();
					}
				});
				request.setHandler( areaHandler );
				request.setUrl(url);
				request.sendRequest();
			} else {
				synchronized ( mFinishSynzServer ) {
					mFinishSynzServer.set ( mFinishSynzServer.get()
							| SYNZ_AREA_TABLES );
				}
			}
			
			//Tables
			TableJsonHandler tableHandler = new TableJsonHandler();
			if ( isSynz || tableHandler.isSynz() ) {
				request = new HttpRequest();
				request.setContext(this);
				url = getResources().getString(R.string.url_table) + action;
				tableHandler.SetOnCompleted(new OnCompleted() {
					
					@Override
					public void Finish() {
						// TODO Auto-generated method stub
						synchronized ( mFinishSynzServer ) {
							mFinishSynzServer.set ( mFinishSynzServer.get()
									| SYNZ_TABLE_TABLES );
							if ( isFinishSynz() ) {
								dismissProgress();
								dumyData();
							}
						}
					}

					@Override
					public void Failed() {
						// TODO Auto-generated method stub
						dismissProgress();
						dumyData();
					}
				});
				request.setHandler( tableHandler );
				request.setUrl(url);
				request.sendRequest();
			} else {
				synchronized ( mFinishSynzServer ) {
					mFinishSynzServer.set ( mFinishSynzServer.get()
							| SYNZ_TABLE_TABLES );
				}
			}
			
			if ( isFinishSynz() ) {
				dumyData();
			} else {
				showProgress(R.string.updating);
			}

		}catch (Exception e) {
			Log.e(TAG, e.getMessage(), e);
		}
	}

	private void dumyData() {
		showProgress(R.string.loading);
		FoodsTask foodsTask = new FoodsTask(getApplicationContext(),
				new IDataEventHandler<ArrayList<Category>>() {

					@Override
					public void onNotify(ArrayList<Category> data) {
						if (mIsDestroy) {
							return;
						}
						LogUtils.logError(TAG, "Finish loading foods");
						synchronized (mFinishLoadData) {
							// update UI.
							mCategories = data;
							mFinishLoadData.set(mFinishLoadData.get()
									| FINISH_LOAD_FOODS);
							if (isFinishLoading()) {
								dismissProgress();
								initlayout();
							}
						}

					}
				});
		foodsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

		// dumy areas data.
		AreasTask areasTask = new AreasTask(getApplicationContext(),
				new IDataEventHandler<ArrayList<Area>>() {

					@Override
					public void onNotify(ArrayList<Area> data) {
						if (mIsDestroy) {
							return;
						}
						LogUtils.logError(TAG, "Finish loading areas");
						synchronized (mFinishLoadData) {
							mAreas = data;
							mTables = this.loadTables(data); 
							mFinishLoadData.set(mFinishLoadData.get()
									| FINISH_LOAD_AREAS);
							if (isFinishLoading()) {
								dismissProgress();
								initlayout();
							}
						}

					}
					
					private ArrayList<Table> loadTables(ArrayList<Area> areas) {
						if (areas == null || areas.isEmpty()) {
							return null;
						}
						
						ArrayList<Table> ret = new ArrayList<Table>();
						ArrayList<Table> temp;
						int tableCount = 0;
						for (Area area : areas) {
							area.setStartTableIndex(tableCount);
							
							temp = area.getTables();
							if (temp == null || temp.isEmpty()) {
								continue;
							}
							
							ret.addAll(temp);
							
							tableCount += temp.size();
						}
						
						return ret;
					}
				});
		areasTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

		OrderQueryTask orderTask = new OrderQueryTask(getApplicationContext(),
				new IDataEventHandler<ArrayList<Order>>() {

					@Override
					public void onNotify(ArrayList<Order> data) {
						if (mIsDestroy) {
							return;
						}
						LogUtils.logError(TAG, "Finish loading orders");
						synchronized (mFinishLoadData) {
							mOrderTempFromDatabase = data;
							mFinishLoadData.set(mFinishLoadData.get()
									| FINISH_LOAD_ORDERS);
							if (isFinishLoading()) {
								dismissProgress();
								initlayout();
							}

						}
					}

				}, true);
		orderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

		OrderQueryTask invoiceTask = new OrderQueryTask(getApplicationContext(),
				new IDataEventHandler<ArrayList<Order>>() {

					@Override
					public void onNotify(ArrayList<Order> data) {
						if (mIsDestroy) {
							return;
						}
						LogUtils.logError(TAG, "Finish loading invoices");
						synchronized (mFinishLoadData) {
							mInvoiceFromDatabase = data;
							mFinishLoadData.set(mFinishLoadData.get()
									| FINISH_LOAD_INVOICES);
							if (isFinishLoading()) {
								dismissProgress();
								initlayout();
							}

						}
					}

				}, false);
		invoiceTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
	}

	private boolean isFinishSaving() {
		return (mFinishSaveData.get() == (FINISH_SAVE_ORDERS | FINISH_SAVE_INVOICES));
	}

	private boolean isFinishLoading() {
		return (mFinishLoadData.get() == (FINISH_LOAD_FOODS
				| FINISH_LOAD_ORDERS | FINISH_LOAD_AREAS | FINISH_LOAD_INVOICES));
	}

	private boolean isFinishSynz() {
		return (mFinishSynzServer.get() == (SYNZ_CATEGORY_TABLES
				| SYNZ_SUBCATEGORY_TABLES | SYNZ_FOOD_TABLES | SYNZ_AREA_TABLES | SYNZ_TABLE_TABLES));
	}
	/**
	 * initialize layout.
	 */
	private void initlayout() {
		this.tabHost = (TabHost) findViewById(android.R.id.tabhost);
        // setup must be called if you are not inflating the tabhost from XML
		this.tabHost.setup();

		TabSpec spec1 = this.tabHost.newTabSpec("Order");
		spec1.setIndicator("Dat mon");
		spec1.setContent(R.id.order_layout);

		TabSpec spec2 = this.tabHost.newTabSpec("Invoice");
		spec2.setIndicator("Hoa don");
		spec2.setContent(R.id.invoice_layout);

		TabSpec spec3 = this.tabHost.newTabSpec("Table join/split");
		spec3.setIndicator("Tach nhap ban");
		spec3.setContent(R.id.table_join_split_layout);

		this.tabHost.addTab(spec1);
		this.tabHost.addTab(spec2);
		this.tabHost.addTab(spec3);
		this.tabHost.setCurrentTab(1);
		this.tabHost.setCurrentTab(0);

		// text view.
		this.mBtOrder = (Button) findViewById(R.id.main_bt_order);
		this.mBtOrder.setOnClickListener(this);
		this.mBtOrder.setSelected(true);
		this.mBtInvoice = (Button) findViewById(R.id.main_bt_invoice);
		this.mBtInvoice.setOnClickListener(this);
		this.mBtTableJoinSplit = (Button) findViewById(R.id.main_bt_table_join_split);
		this.mBtTableJoinSplit.setOnClickListener(this);

		this.initOrderLayout();
		this.initInvoiceLayout();
		this.initTableJoinSplitLayout();

		this.updateLanguage();
	}
	
	private void initOrderLayout() {
		//get control id
		this.mTvArea = (TextView) findViewById(R.id.main_tv_area);
		this.mTvTable = (TextView) findViewById(R.id.main_tv_table);
		this.mTvListOrders = (TextView) findViewById(R.id.main_tv_list_orders);
		this.mTvListInvoices = (TextView) findViewById(R.id.main_tv_list_invoices);
		this.mTvTotalMoney = (TextView) findViewById(R.id.main_tv_total_money);
		this.mLvOrderDetails = (ListView) findViewById(R.id.main_lv_orders);
		// init discount
		this.mBtDiscount = (Button) findViewById(R.id.main_bt_discount);
		this.mBtDiscount.setOnClickListener(this);

		this.mBtLanguage = (Button) findViewById(R.id.main_bt_language);
		this.mBtLanguage.setOnClickListener(this);

		this.mBtPayment = (Button) findViewById(R.id.main_bt_payment);
		this.mBtPayment.setOnClickListener(this);

		this.mBtPrintOrder = (Button) findViewById(R.id.main_bt_printorder);
		this.mBtPrintOrder.setOnClickListener(this);
		// subcategory.
		this.mLlSubCategories = (LinearLayout) findViewById(R.id.main_ll_subcategories);
		// init layout of foods.
		this.mGvFoods = (GridView) findViewById(R.id.main_gv_foods);

		if ( mAreas == null || mAreas.size() < 1 ) {
			return;
		}

		// init spinner to display area names.
		Spinner s2 = (Spinner) findViewById(R.id.main_spinner_areas);
		this.mAreaAdapter = new AreaAdapter(getApplicationContext(), 0, mAreas);
		this.mAreaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s2.setAdapter(this.mAreaAdapter);
		s2.setOnItemSelectedListener(this.mAreaSelected);
		
		// init spinner to display table names.
		Spinner s1 = (Spinner) findViewById(R.id.main_spinner_tables);
		this.mTableAdapter = new TableAdapter(getApplicationContext(), 0,
				this.mAreas.get(0).getTables());
		this.mTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s1.setAdapter(this.mTableAdapter);
		s1.setOnItemSelectedListener(this.mTableSelected);

		// initialize list orders.
		this.initializeOrderList();
		
		this.mCurrentAreaIndex = 0;
		this.mCurrentTableIndex = 0;
		// resetCurrentSubCategories();
		this.mFoodAdapter = new FoodAdapter(getApplicationContext(), 0,
				this.mCurrentFoods, this.mCacheManager, this.mOrders.get(this.mCurrentTableIndex));
		this.mGvFoods.setAdapter(this.mFoodAdapter);
		this.mGvFoods.setOnItemClickListener(this.mFoodItemClickListener);
		this.mGvFoods.setOnScrollListener(this);

		// init list of orders.
		if (this.mOrderFooterView == null) {
			initOrderFooter();
		}

		if (this.mOrderFooterView != null) {
			this.mLvOrderDetails.addFooterView(this.mOrderFooterView);
		}

		this.mOrderAdapter = new OrderAdapter(getBaseContext(), this.mOrders.get(
				this.mCurrentTableIndex).getOrdersDetails());
		this.mLvOrderDetails.setAdapter(this.mOrderAdapter);
		this.mLvOrderDetails.setOnItemClickListener(this.mOrderDetailItemClickListener);

		// init amounts
		this.mTvTotalMoney.setText("" + this.mOrders.get(mCurrentTableIndex).getTotal());

		ImageView ivUser = (ImageView) findViewById(R.id.user_iv_icon);
		ivUser.setOnClickListener(this);

		// init category layout.
		this.mCurrentCategoryIndex = 0;
		initCategoryLayout();
		// // update UI for subcategory.
		// resetCurrentSubCategories();
		if (!this.mIsPause) {
			startDecoder();
		}
		
		this.updateTotalMoney();
		
	}
	
	private void initializeOrderList() {
		if (mTables != null) {
			mOrders = new ArrayList<Order>();
			for (int i = 0; i < mTables.size(); i++) {
				Order order = null;
				// find the order from database.
				if (mOrderTempFromDatabase != null
						&& mOrderTempFromDatabase.size() > 0) {
					for (int j = 0; j < mOrderTempFromDatabase.size(); j++) {
						if (mOrderTempFromDatabase.get(j).getTableID() == mTables
								.get(i).getId()) {
							order = mOrderTempFromDatabase.get(j);
							order.setAreaID(mTables.get(i).getAreaID());
							order.setAreaName(mTables.get(i).getAreaName());
							mOrderTempFromDatabase.remove(j);
							break;
						}
					}
				}
				
				if (order == null) {
					order = new Order();

					order.setId(PrefUtils.getInt(getApplicationContext(),
							Constants.PREF_ORDER_ID, 0) + 1);
					PrefUtils.writeInt(getApplicationContext(),
							Constants.PREF_ORDER_ID, order.getId());

					// set table id.
					order.setTableID(mTables.get(i).getId());
					order.setTable(mTables.get(i).getName());
					order.setAreaID(mTables.get(i).getAreaID());
					order.setAreaName(mTables.get(i).getAreaName());
				}
				
				mOrders.add(order);
			}
		}
		
	}
	
	private void initInvoiceLayout() {

		// initialize invoice list.
		if (this.mInvoiceFromDatabase == null) {
			this.mInvoices = new ArrayList<Order>();
		} else {
			this.mInvoices = this.mInvoiceFromDatabase;
			this.sendInvociesToServer(this.mInvoices);
		}
		
		this.mTotalMoneyOfInvoices = 0;
		this.mAllInvoices = new ArrayList<Order>();
		for (Order invoice : this.mInvoices) {
			this.mAllInvoices.add(invoice);
			this.mTotalMoneyOfInvoices += invoice.getTotalMoneyWillPay();
		}

		// init list of invoices.
		this.mLvInvoices = (ListView) findViewById(R.id.main_lv_invoices);
		this.mInvoiceAdapter = new InvoiceAdapter(getBaseContext(), this.mInvoices);
		this.mLvInvoices.setAdapter(this.mInvoiceAdapter);
		this.mLvInvoices.setOnItemClickListener(this.mInvoiceItemClickListener);

		// init amount
		this.mTvTotalMoneyOfInvoices = (TextView) findViewById(R.id.main_tv_total_money_of_invoices);
		this.mTvTotalMoneyOfInvoices.setText(CommonUtils.convertMoneyToString(this.mTotalMoneyOfInvoices));
		
		if (this.mInvoices.size() > 0) {
			this.mCurrentInvoiceSelectedIndex = 0;
			this.initInvoiceDetailLayout();
		}
	}
	
	private void initTableJoinSplitLayout() {
		//get control id
		this.mTv1stArea = (TextView) findViewById(R.id.main_tv_1st_area);
		this.mTv1stTable = (TextView) findViewById(R.id.main_tv_1st_table);
		this.mTv1stListOrders = (TextView) findViewById(R.id.main_tv_1st_list_orders);

		this.mTv2ndArea = (TextView) findViewById(R.id.main_tv_2nd_area);
		this.mTv2ndTable = (TextView) findViewById(R.id.main_tv_2nd_table);
		this.mTv2ndListOrders = (TextView) findViewById(R.id.main_tv_2nd_list_orders);
		this.mLv1stOrderDetails = (ListView) findViewById(R.id.main_lv_1st_orders);
		this.mLv2ndOrderDetails = (ListView) findViewById(R.id.main_lv_2nd_orders);

		if ( mAreas == null || mAreas.size() < 1 ) {
			return;
		}

		// init spinner to display 1st area names.
		Spinner s1 = (Spinner) findViewById(R.id.main_spinner_1st_areas);
		this.m1stAreaAdapter = new AreaAdapter(getApplicationContext(), 0, mAreas);
		this.m1stAreaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s1.setAdapter(this.m1stAreaAdapter);
		s1.setOnItemSelectedListener(this.m1stAreaSelected);
		
		// init spinner to display 1st table names.
		Spinner s2 = (Spinner) findViewById(R.id.main_spinner_1st_tables);
		this.m1stTableAdapter = new TableAdapter(getApplicationContext(), 0,
				this.mAreas.get(0).getTables());
		this.m1stTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s2.setAdapter(this.m1stTableAdapter);
		s2.setOnItemSelectedListener(this.m1stTableSelected);
		
		// init spinner to display 2nd area names.
		Spinner s3 = (Spinner) findViewById(R.id.main_spinner_2nd_areas);
		this.m2ndAreaAdapter = new AreaAdapter(getApplicationContext(), 0, mAreas);
		this.m2ndAreaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s3.setAdapter(this.m2ndAreaAdapter);
		s3.setOnItemSelectedListener(this.m2ndAreaSelected);
		
		// init spinner to display 2nd table names.
		Spinner s4 = (Spinner) findViewById(R.id.main_spinner_2nd_tables);
		this.m2ndTableAdapter = new TableAdapter(getApplicationContext(), 0,
				this.mAreas.get(0).getTables());
		this.m2ndTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		s4.setAdapter(this.m2ndTableAdapter);
		s4.setOnItemSelectedListener(this.m2ndTableSelected);
		
		this.m1stCurrentAreaIndex = 0;
		this.m1stCurrentTableIndex = 0;
		
		this.m2ndCurrentAreaIndex = 0;
		this.m2ndCurrentTableIndex = 0;

		// init lists of orders.
		this.m1stOrderAdapter = new InvoiceDetailAdapter(getBaseContext(), this.mOrders.get(
				this.m1stCurrentTableIndex).getOrdersDetails());
		this.mLv1stOrderDetails.setAdapter(this.m1stOrderAdapter);
		this.mLv1stOrderDetails.setOnItemClickListener(this.m1stOrderDetailItemClickListener);

		
		this.m2ndOrderAdapter = new InvoiceDetailAdapter(getBaseContext(), this.mOrders.get(
				this.m2ndCurrentTableIndex).getOrdersDetails());
		this.mLv2ndOrderDetails.setAdapter(this.m2ndOrderAdapter);
		this.mLv2ndOrderDetails.setOnItemClickListener(this.m2ndOrderDetailItemClickListener);
	}

	private void initInvoiceDetailLayout() {
		Order invoice = this.mInvoices.get(this.mCurrentInvoiceSelectedIndex);
		
		// init title.
		this.mTvInvoiceDetailsTitle = (TextView) findViewById(R.id.main_tv_invoice_details_title);
		this.mTvInvoiceDetailsTitle.setText(invoice.getInvoiceTitle());
		
		// init creator.
		this.mTvInvoiceDetailsCreator = (TextView) findViewById(R.id.main_tv_invoice_details_creator);
		this.mTvInvoiceDetailsCreator.setText( getResources().getString(R.string.create_date_title) + " admin");
		// init table.
		this.mTvInvoiceDetailsTable = (TextView) findViewById(R.id.main_tv_invoice_details_table);
		this.mTvInvoiceDetailsTable.setText(String.format("Ban: %s - %s",
				invoice.getAreaName(), invoice.getTable()));
		
		// init date.
		this.mTvInvoiceDetailsDate = (TextView) findViewById(R.id.main_tv_invoice_details_date);
		this.mTvInvoiceDetailsDate.setText(invoice.getEnd());

		// init list of invoice details.
		this.mLvInvoiceDetails = (ListView) findViewById(R.id.main_lv_invoice_details);
		if (this.mInvoiceFooterView == null) {
			initInvoiceFooter();
		}

		if (this.mInvoiceFooterView != null) {
			this.mLvInvoiceDetails.addFooterView(this.mInvoiceFooterView);
		}

		this.mInvoiceDetailAdapter = new InvoiceDetailAdapter(getBaseContext(), invoice.getOrdersDetails());
		this.mLvInvoiceDetails.setAdapter(this.mInvoiceDetailAdapter);
		
		this.updateInvoiceTotalMoney();
	}
	
	private void initOrderFooter() {
		mOrderFooterView = getLayoutInflater().inflate(R.layout.order_footer,
				null);
		setTvOrderFooterTotalTitle((TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_total_title));
		mTvOrderFooterTotalValue = (TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_total_value);
		setTvOrderFooterDiscountTitle((TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_discount_title));
		mTvOrderFooterDiscountValue = (TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_discount_value);
		mTvOrderFooterDiscountTotalMoney = (TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_discount_total_money);
		mTvOrderFooterDiscountName = (TextView) mOrderFooterView
				.findViewById(R.id.order_footer_tv_discount_name);
		setLlOrderFooterTotal((LinearLayout) mOrderFooterView
				.findViewById(R.id.order_footer_ll_total));
		mLlOrderFooterDiscount = (LinearLayout) mOrderFooterView
				.findViewById(R.id.order_footer_ll_discount);
	}
	
	private void initInvoiceFooter() {
		mInvoiceFooterView = getLayoutInflater().inflate(R.layout.invoice_footer, null);
		mTvInvoiceFooterTotalTitle = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_total_title);
		mTvInvoiceFooterTotalValue = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_total_value);
		mTvInvoiceFooterDiscountTitle = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_discount_title);
		mTvInvoiceFooterDiscountValue = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_discount_value);
		mTvInvoiceFooterDiscountTotalMoney = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_discount_total_money);
		mTvInvoiceFooterDiscountName = (TextView) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_tv_discount_name);
		mLlInvoiceFooterTotal = (LinearLayout) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_ll_total);
		mLlInvoiceFooterDiscount = (LinearLayout) mInvoiceFooterView
				.findViewById(R.id.invoice_footer_ll_discount);
	}

	private void updateTotalMoney() {
		if (mOrders == null || mOrders.size() <= mCurrentTableIndex) {
			return;
		}
		// update footer view.
		double totalDiscountMoney = 0;
		String moneyUnit = getString(R.string.money_unit);
		Order order = mOrders.get(mCurrentTableIndex);
		Discount discount = order.getDiscount();
		if (discount != null
				&& (discount.getMoney() > 0 || discount.getPercent() > 0)) {
			// hasDiscount = true;

			if (discount.getMoney() > 0) {
				mTvOrderFooterDiscountValue.setText("-" + discount.getMoney()
						+ moneyUnit);
			} else {
				mTvOrderFooterDiscountValue.setText("-" + discount.getPercent()
						+ "%");
			}
			totalDiscountMoney = discount.getTotalDiscountMoney(order
					.getTotal());

		}
		if (totalDiscountMoney <= 0) {
			mLlOrderFooterDiscount.setVisibility(View.GONE);
		} else {
			mLlOrderFooterDiscount.setVisibility(View.VISIBLE);
			mTvOrderFooterDiscountTotalMoney.setText(""
					+ CommonUtils.convertMoneyToString(totalDiscountMoney)
					+ moneyUnit);
			mTvOrderFooterDiscountName.setText(discount.getName());
		}
		// update total money.
		if (order.getTotal() > 0) {
			mTvOrderFooterTotalValue.setText(""
					+ CommonUtils.convertMoneyToString(order.getTotal())
					+ moneyUnit);
		} else {
			mTvOrderFooterTotalValue.setText("");
		}

		mTvTotalMoney.setText(CommonUtils.convertMoneyToString(order.getTotal()
				- totalDiscountMoney)
				+ moneyUnit);
	}

	private void updateInvoiceTotalMoney() {
		if (mInvoices == null || mInvoices.size() <= mCurrentInvoiceSelectedIndex ||
				mCurrentInvoiceSelectedIndex < 0) {
			return;
		}
		
		// update footer view.
		double totalDiscountMoney = 0;
		String moneyUnit = getString(R.string.money_unit);
		Order order = mInvoices.get(mCurrentInvoiceSelectedIndex);
		Discount discount = order.getDiscount();
		if (discount != null
				&& (discount.getMoney() > 0 || discount.getPercent() > 0)) {

			if (discount.getMoney() > 0) {
				mTvInvoiceFooterDiscountValue.setText("-" + discount.getMoney() + moneyUnit);
			} else {
				mTvInvoiceFooterDiscountValue.setText("-" + discount.getPercent() + "%");
			}
			
			totalDiscountMoney = discount.getTotalDiscountMoney(order.getTotal());
		}
		
		if (totalDiscountMoney <= 0) {
			mLlInvoiceFooterDiscount.setVisibility(View.GONE);
		} else {
			mLlInvoiceFooterDiscount.setVisibility(View.VISIBLE);
			mTvInvoiceFooterDiscountTotalMoney.setText(""
					+ CommonUtils.convertMoneyToString(totalDiscountMoney)
					+ moneyUnit);
			mTvInvoiceFooterDiscountName.setText(discount.getName());
		}
		
		// update total money.
		if (order.getTotal() > 0) {
			mTvInvoiceFooterTotalValue.setText(""
					+ CommonUtils.convertMoneyToString(order.getTotal())
					+ moneyUnit);
		} else {
			mTvInvoiceFooterTotalValue.setText("");
		}


		// init total.
		this.mTvInvoiceDetailsTotal = (TextView) findViewById(R.id.main_tv_invoice_details_total);
		this.mTvInvoiceDetailsTotal.setText(CommonUtils.convertMoneyToString(order.getTotal()
				- totalDiscountMoney) + moneyUnit);
	}

	/**
	 * update text of all views based on current language.
	 */
	private void updateLanguage() {
		// update language for language button.
		switch (MyCoffeeApplication.mLanguage) {
		case Constants.LANGUAGE_VN:
			mBtLanguage.setText(getString(R.string.tv_language_vn));
			mBtDiscount.setText(getString(R.string.tv_discount_vn));
			mBtPayment.setText(getString(R.string.tv_payment_vn));
			mBtOrder.setText(getString(R.string.tv_order_vn));
			mBtInvoice.setText(getString(R.string.tv_invoice_vn));
			mBtTableJoinSplit.setText(getString(R.string.tv_table_join_split_vn));
			mTvArea.setText(getString(R.string.tv_area_vn));
			mTvTable.setText(getString(R.string.tv_table_vn));
			mTvListOrders.setText(getString(R.string.tv_list_of_orders_vn));
			mTvListInvoices.setText(getString(R.string.tv_list_of_invoices_vn));
			mTv1stArea.setText(getString(R.string.tv_area_vn));
			mTv1stTable.setText(getString(R.string.tv_table_vn));
			mTv1stListOrders.setText(getString(R.string.tv_list_of_orders_vn));
			mTv2ndArea.setText(getString(R.string.tv_area_vn));
			mTv2ndTable.setText(getString(R.string.tv_table_vn));
			mTv2ndListOrders.setText(getString(R.string.tv_list_of_orders_vn));
			break;
		case Constants.LANGUAGE_EN:
			mBtLanguage.setText(getString(R.string.tv_language_en));
			mBtDiscount.setText(getString(R.string.tv_discount_en));
			mBtPayment.setText(getString(R.string.tv_payment_en));
			mBtOrder.setText(getString(R.string.tv_order_en));
			mBtInvoice.setText(getString(R.string.tv_invoice_en));
			mBtTableJoinSplit.setText(getString(R.string.tv_table_join_split_en));
			mTvArea.setText(getString(R.string.tv_area_en));
			mTvTable.setText(getString(R.string.tv_table_en));
			mTvListOrders.setText(getString(R.string.tv_list_of_orders_en));
			mTvListInvoices.setText(getString(R.string.tv_list_of_invoices_en));
			mTv1stArea.setText(getString(R.string.tv_area_en));
			mTv1stTable.setText(getString(R.string.tv_table_en));
			mTv1stListOrders.setText(getString(R.string.tv_list_of_orders_en));
			mTv2ndArea.setText(getString(R.string.tv_area_en));
			mTv2ndTable.setText(getString(R.string.tv_table_en));
			mTv2ndListOrders.setText(getString(R.string.tv_list_of_orders_en));
			break;
		case Constants.LANGUAGE_DE:
			mBtLanguage.setText(getString(R.string.tv_language_de));
			mBtDiscount.setText(getString(R.string.tv_discount_de));
			mBtPayment.setText(getString(R.string.tv_payment_de));
			mBtOrder.setText(getString(R.string.tv_order_de));
			mBtInvoice.setText(getString(R.string.tv_invoice_de));
			mBtTableJoinSplit.setText(getString(R.string.tv_table_join_split_de));
			mTvArea.setText(getString(R.string.tv_area_de));
			mTvTable.setText(getString(R.string.tv_table_de));
			mTvListOrders.setText(getString(R.string.tv_list_of_orders_de));
			mTvListInvoices.setText(getString(R.string.tv_list_of_invoices_de));
			mTv1stArea.setText(getString(R.string.tv_area_de));
			mTv1stTable.setText(getString(R.string.tv_table_de));
			mTv1stListOrders.setText(getString(R.string.tv_list_of_orders_de));
			mTv2ndArea.setText(getString(R.string.tv_area_de));
			mTv2ndTable.setText(getString(R.string.tv_table_de));
			mTv2ndListOrders.setText(getString(R.string.tv_list_of_orders_de));
			break;
		default:
			break;
		}

		if ( mCategories == null || mCategories.size() < 1 ) {
			return;
		}

		// update language for categories.
		if (mLlCategories != null) {
			for (int i = 0; i < mLlCategories.getChildCount(); i++) {
				View childView = mLlCategories.getChildAt(i);
				TextView tvContent = (TextView) childView.getTag();
				tvContent.setText(mCategories.get(i)
						.getNameFollowCurrentLanguage());
			}
		}

		// update language for subcategories.
		if (mLlSubCategories != null) {
			ArrayList<SubCategory> subCategories = mCategories.get(
					mCurrentCategoryIndex).getSubCategories();
			if (subCategories != null && subCategories.size() > 0) {
				for (int i = 0; i < mLlSubCategories.getChildCount(); i++) {
					TextView childView = (TextView) mLlSubCategories
							.getChildAt(i);
					childView.setText(subCategories.get(i)
							.getNameFollowCurrentLanguage());
				}
			}

		}
		
		// update language for foods.
		if (mFoodAdapter != null) {
			mFoodAdapter.notifyDataSetChanged();
		}
		
		// update language for list of orders.
		if (mOrderAdapter != null) {
			mOrderAdapter.notifyDataSetChanged();
		}

		if (m1stOrderAdapter != null) {
			m1stOrderAdapter.notifyDataSetChanged();
		}

		if (m2ndOrderAdapter != null) {
			m2ndOrderAdapter.notifyDataSetChanged();
		}

		if (mTableAdapter != null) {
			mTableAdapter.notifyDataSetChanged();
		}

		if (mAreaAdapter != null) {
			mAreaAdapter.notifyDataSetChanged();
		}

		if (m1stTableAdapter != null) {
			m1stTableAdapter.notifyDataSetChanged();
		}

		if (m1stAreaAdapter != null) {
			m1stAreaAdapter.notifyDataSetChanged();
		}

		if (m2ndTableAdapter != null) {
			m2ndTableAdapter.notifyDataSetChanged();
		}

		if (m2ndAreaAdapter != null) {
			m2ndAreaAdapter.notifyDataSetChanged();
		}
		
		// update language for list of invoices.
		if (mInvoiceAdapter != null) {
			mInvoiceAdapter.notifyDataSetChanged();
		}

		if (mInvoiceDetailAdapter != null) {
			mInvoiceDetailAdapter.notifyDataSetChanged();
		}
	}

	/**
	 * start decoder to decode stickers image.
	 */
	private void startDecoder() {
		if (mCacheManager == null) {
			mCacheManager = new CacheManager(getApplicationContext(),
					mCurrentFoods, 30, this);
			mCacheManager.setVisiblePos(mGvFoods.getFirstVisiblePosition(),
					mGvFoods.getLastVisiblePosition());
			mCacheManager.setMaxSize(100);
			mFoodAdapter.setCacheManager(mCacheManager);
		}
		if (mCacheManager != null && mCacheManager.isStop()) {
			mCacheManager.setPause(false);
			mCacheManager.execute();
		}
	}

	@Override
	public void onFinishDecode(final Integer[] values) {
		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				int pos = values[0];
				if (pos >= mGvFoods.getFirstVisiblePosition()
						&& pos <= mGvFoods.getLastVisiblePosition()) {
					View view = mGvFoods.getChildAt(pos
							- mGvFoods.getFirstVisiblePosition());
					mFoodAdapter.updateImage(pos, view);
				}
			}
		});
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		if (mCacheManager == null) {
			return;
		}
		mCacheManager.setVisiblePos(firstVisibleItem, firstVisibleItem
				+ visibleItemCount - 1);
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {

	}

	/**
	 * Receive action when user select an item of list foods.
	 */
	private OnItemClickListener mFoodItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> arg0, View view, int pos,
				long arg3) {
			// order this food, so upadte selected for it.
			if (mCurrentFoods == null || pos < 0 || pos >= mCurrentFoods.size()) {
				return;
			}

			Food food = mCurrentFoods.get(pos);
			Order currentOrder = mOrders.get(mCurrentTableIndex);

			currentOrder.orderForFood(food);

			if (mFoodAdapter != null) {
				mFoodAdapter.updateAmount(view, pos);
			}

			if (mOrderAdapter != null) {
				mOrderAdapter.notifyDataSetChanged();
			}

			// mTvTotalMoney.setText("" + currentOrder.getTotal());
			updateTotalMoney();
		}
	};

	/**
	 * Receive action when user select an item of list subCategories.
	 */
	private OnClickListener mSubCategoryItemClickListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			if (v == null) {
				return;
			}
			int pos = (Integer) v.getTag();

			if (mCurrentSubCategoryIndex != pos) {

				setSubCategoryItemSelected(pos);
			}

		}
	};

	/**
	 * Receive action when user select an item of list tables.
	 */
	private OnItemSelectedListener mTableSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			int currentPos = mCurrentTableIndex - mAreas.get(mCurrentAreaIndex).getStartTableIndex();
			if (currentPos != pos) {
				mCurrentTableIndex = mAreas.get(mCurrentAreaIndex).getStartTableIndex() + pos;
				// reset
				mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
				Order currentOrder = mOrders.get(mCurrentTableIndex);
				// update grid view of foods.
				if (mFoodAdapter != null) {
					mFoodAdapter.setCurrentOrder(currentOrder);
				}
				
				if (mOrderAdapter != null) {
					mOrderAdapter.setCurrentOrder(currentOrder);
				}

				// mTvTotalMoney.setText("" + currentOrder.getTotal());
				updateTotalMoney();
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};

	private OnItemSelectedListener m1stTableSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			int currentPos = m1stCurrentTableIndex - mAreas.get(m1stCurrentAreaIndex).getStartTableIndex();
			if (currentPos != pos) {
				m1stCurrentTableIndex = mAreas.get(m1stCurrentAreaIndex).getStartTableIndex() + pos;
				// reset
				Order currentOrder = mOrders.get(m1stCurrentTableIndex);
				if (m1stOrderAdapter != null) {
					m1stOrderAdapter.setCurrentInvoice(currentOrder);
				}
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};

	private OnItemSelectedListener m2ndTableSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			int currentPos = m2ndCurrentTableIndex - mAreas.get(m2ndCurrentAreaIndex).getStartTableIndex();
			if (currentPos != pos) {
				m2ndCurrentTableIndex = mAreas.get(m2ndCurrentAreaIndex).getStartTableIndex() + pos;
				// reset
				Order currentOrder = mOrders.get(m2ndCurrentTableIndex);
				if (m2ndOrderAdapter != null) {
					m2ndOrderAdapter.setCurrentInvoice(currentOrder);
				}
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};
	
	/**
	 * new [ngoc]: need update to replace table by area.
	 * Receive action when user select an item of list areas.
	 */
	private OnItemSelectedListener mAreaSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (mCurrentAreaIndex != pos) {
				mCurrentAreaIndex = pos;

				// reset table list in Table spinner.
				Spinner s1 = (Spinner) findViewById(R.id.main_spinner_tables);
				mTableAdapter = new TableAdapter(getApplicationContext(), 0,
						mAreas.get(mCurrentAreaIndex).getTables());
				mTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				s1.setAdapter(mTableAdapter);

				// reset table index.
				mCurrentTableIndex = mAreas.get(mCurrentAreaIndex).getStartTableIndex();
				
				mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
				Order currentOrder = mOrders.get(mCurrentTableIndex);
				// update grid view of foods.
				if (mFoodAdapter != null) {
					mFoodAdapter.setCurrentOrder(currentOrder);
				}
				
				if (mOrderAdapter != null) {
					mOrderAdapter.setCurrentOrder(currentOrder);
				}

				// mTvTotalMoney.setText("" + currentOrder.getTotal());
				updateTotalMoney();
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};

	private OnItemSelectedListener m1stAreaSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (m1stCurrentAreaIndex != pos) {
				m1stCurrentAreaIndex = pos;

				// reset table list in Table spinner.
				Spinner s1 = (Spinner) findViewById(R.id.main_spinner_1st_tables);
				m1stTableAdapter = new TableAdapter(getApplicationContext(), 0,
						mAreas.get(m1stCurrentAreaIndex).getTables());
				m1stTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				s1.setAdapter(m1stTableAdapter);

				// reset table index.
				m1stCurrentTableIndex = mAreas.get(m1stCurrentAreaIndex).getStartTableIndex();
				
				Order currentOrder = mOrders.get(m1stCurrentTableIndex);
				
				if (m1stOrderAdapter != null) {
					m1stOrderAdapter.setCurrentInvoice(currentOrder);
				}
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};

	private OnItemSelectedListener m2ndAreaSelected = new OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (m2ndCurrentAreaIndex != pos) {
				m2ndCurrentAreaIndex = pos;

				// reset table list in Table spinner.
				Spinner s1 = (Spinner) findViewById(R.id.main_spinner_2nd_tables);
				m2ndTableAdapter = new TableAdapter(getApplicationContext(), 0,
						mAreas.get(m2ndCurrentAreaIndex).getTables());
				m2ndTableAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				s1.setAdapter(m2ndTableAdapter);

				// reset table index.
				m2ndCurrentTableIndex = mAreas.get(m2ndCurrentAreaIndex).getStartTableIndex();
				
				Order currentOrder = mOrders.get(m2ndCurrentTableIndex);
				
				if (m2ndOrderAdapter != null) {
					m2ndOrderAdapter.setCurrentInvoice(currentOrder);
				}
			}
		}

		@Override
		public void onNothingSelected(AdapterView<?> arg0) {

		}
	};
	
	/**
	 * Receive action when user select an item of list categories.
	 */
	private OnClickListener mCategoryItemClickListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			if (v == null) {
				return;
			}
			int pos = (Integer) v.getTag();
			if (mCurrentCategoryIndex == pos) {
				return;
			}
			setCategoryItemSelected(pos);

			// update list of subCategory.
			// resetCurrentSubCategories();

		}
	};

	private OnItemClickListener mOrderDetailItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (mCurrentOrderDetailSelectedIndex == pos) {
				mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
			} else {
				mCurrentOrderDetailSelectedIndex = pos;
			}
			
			if (mOrderAdapter != null) {
				mOrderAdapter
						.setOrderDetailSelectedIndex(mCurrentOrderDetailSelectedIndex);
			}
		}
	};

	private OnItemClickListener m1stOrderDetailItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (m1stOrderAdapter == null || m2ndOrderAdapter == null) {
				return;
			}

			Order current1stOrder = mOrders.get(m1stCurrentTableIndex);
			OrdersDetail detail = (OrdersDetail)m1stOrderAdapter.getItem(pos);

			Order current2ndOrder = mOrders.get(m2ndCurrentTableIndex);
			current2ndOrder.orderForFood(detail.getFood());

			current1stOrder.decreaseOrderDetail(pos);
			
			m1stOrderAdapter.notifyDataSetChanged();
			m2ndOrderAdapter.notifyDataSetChanged();
		}
	};

	private OnItemClickListener m2ndOrderDetailItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			if (m1stOrderAdapter == null || m2ndOrderAdapter == null) {
				return;
			}

			Order current2ndOrder = mOrders.get(m2ndCurrentTableIndex);
			OrdersDetail detail = (OrdersDetail)m2ndOrderAdapter.getItem(pos);

			Order current1stOrder = mOrders.get(m1stCurrentTableIndex);
			current1stOrder.orderForFood(detail.getFood());

			current2ndOrder.decreaseOrderDetail(pos);
			
			m1stOrderAdapter.notifyDataSetChanged();
			m2ndOrderAdapter.notifyDataSetChanged();
		}
	};

	private OnItemClickListener mInvoiceItemClickListener = new OnItemClickListener() {

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int pos,
				long arg3) {
			mCurrentInvoiceSelectedIndex = pos;			

			if ( mInvoiceAdapter != null ) {
				mInvoiceAdapter.setInvoiceSelectedIndex(mCurrentInvoiceSelectedIndex);
			}

			if ( mInvoiceDetailAdapter != null ) {
				Order invoice = mInvoices.get(mCurrentInvoiceSelectedIndex);
				// set title.
				mTvInvoiceDetailsTitle.setText(invoice.getInvoiceTitle());
				// set creator.
				mTvInvoiceDetailsCreator.setText("Nguoi tao: admin");
				// set table.
				mTvInvoiceDetailsTable.setText(String.format("Ban: %s - %s",
						invoice.getAreaName(), invoice.getTable()));
				// set date.
				mTvInvoiceDetailsDate.setText(invoice.getEnd());
				// set list of invoice details.
				mInvoiceDetailAdapter.setCurrentInvoice(invoice);
				// set date.
				// mTvInvoiceDetailsTotal.setText("Tong cong: " + CommonUtils.convertMoneyToString(invoice.getTotalMoneyWillPay()));
				updateInvoiceTotalMoney();
			}
		}
	};
	
	/**
	 * initialize layout of list categories.
	 */
	private void initInvoiceFilterLayout() {
		mLlCategories.removeAllViews();
		String[] array = getResources().getStringArray(R.array.Invoice_filter_vn);
		for (int i = 0; i < array.length; i++) {
			final int position = i;
			View ItemLayout = LayoutInflater.from(
					getApplicationContext()).inflate(R.layout.category_item,
					null);

			TextView tvContent = (TextView) ItemLayout
					.findViewById(R.id.category_item_tv_content);
			((LinearLayout) ItemLayout)
					.setGravity(Gravity.CENTER_VERTICAL);
			tvContent
					.setText(" "+ array[i] + " ");
			tvContent.setGravity(Gravity.CENTER_VERTICAL);
			// update selected status for the first item.
			if (i == 0) {
				tvContent.setTextColor(getResources().getColor(
						R.color.category_background_over_color));
			}
			mLlCategories.addView(ItemLayout, new LayoutParams(
					LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

			ItemLayout.setTag(tvContent);
			tvContent.setTag(i);
			tvContent.setOnClickListener(new OnClickListener() {
				
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					setInvoiceFilterItemSelected(position);
					if ( position == 0 ) {
						MainActivity.this.filterInvoiceByWeek();
					} else {
						MainActivity.this.filterInvoiceByDay();
					}
				}
			});
		}
		
		setInvoiceFilterItemSelected(0);
	}

	private void initSplitJoinTableLayout() {
		mLlCategories.removeAllViews();
	}
	
	private void initCategoryLayout() {
		if (mCategories == null || mCategories.size() == 0) {
			return;
		}
		mLlCategories = (LinearLayout) findViewById(R.id.main_ll_categories);
		mLlCategories.removeAllViews();
		for (int i = 0; i < mCategories.size(); i++) {

			View categoryItemLayout = LayoutInflater.from(
					getApplicationContext()).inflate(R.layout.category_item,
					null);

			TextView tvContent = (TextView) categoryItemLayout
					.findViewById(R.id.category_item_tv_content);
			((LinearLayout) categoryItemLayout)
					.setGravity(Gravity.CENTER_VERTICAL);
			tvContent
					.setText(mCategories.get(i).getNameFollowCurrentLanguage());
			tvContent.setGravity(Gravity.CENTER_VERTICAL);
			// update selected status for the first item.
			if (i == 0) {
				tvContent.setTextColor(getResources().getColor(
						R.color.category_background_over_color));
			}
			mLlCategories.addView(categoryItemLayout, new LayoutParams(
					LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

			categoryItemLayout.setTag(tvContent);
			tvContent.setTag(i);
			tvContent.setOnClickListener(mCategoryItemClickListener);
		}
		mCurrentCategoryIndex = Constants.INVALID_VALUE;
		setCategoryItemSelected(0);
	}

	/**
	 * initialize layout of list sub-categories.
	 */
	private void initSubCategoryLayout() {
		if (mCategories == null || mCategories.size() == 0
				|| mCurrentCategoryIndex < 0
				|| mCurrentCategoryIndex >= mCategories.size()) {
			return;
		}
		// move all view of old subcategories to arrayList.
		for (int i = mLlSubCategories.getChildCount() - 1; i >= 0; i--) {
			View v = mLlSubCategories.getChildAt(i);
			mLlSubCategories.removeViewAt(i);
			mSubCategoryItems.add(v);
			// reset status of selected item.
			if (i == mCurrentSubCategoryIndex) {
				v.setBackgroundColor(getResources().getColor(
						R.color.trasparent_color));
			}
		}
		ArrayList<SubCategory> subCategories = mCategories.get(
				mCurrentCategoryIndex).getSubCategories();

		if (subCategories == null || subCategories.size() == 0) {
			return;
		}

		// create all items for current sub categories.
		for (int i = 0; i < subCategories.size(); i++) {
			View v = null;
			// get from mSubCategoryItems
			if (mSubCategoryItems.size() > 0) {
				v = mSubCategoryItems.get(0);
				mSubCategoryItems.remove(0);
			}
			if (v == null) {
				// create it from xml file.
				v = LayoutInflater.from(getApplicationContext()).inflate(
						R.layout.subcategory_item, null);

			}

			((TextView) v).setText(subCategories.get(i)
					.getNameFollowCurrentLanguage());
			mLlSubCategories.addView(v, new LayoutParams(
					LayoutParams.WRAP_CONTENT, (int) getResources()
							.getDimension(R.dimen.subcategory_height)));
			v.setTag(i);
			v.setOnClickListener(mSubCategoryItemClickListener);

		}
	}

	/**
	 * set position of selected item category.
	 * 
	 * @param pos
	 *            the position that is selected.
	 */
	private void setCategoryItemSelected(int pos) {
		if (mCurrentCategoryIndex != pos) {
			// update status of selected view.
			if (mCurrentCategoryIndex >= 0) {
				View oldSelectedView = mLlCategories
						.getChildAt(mCurrentCategoryIndex);
				TextView oldTvContent = (TextView) oldSelectedView.getTag();

				oldTvContent.setTextColor(getResources().getColor(
						R.color.black_color));
			}
			View selectedView = mLlCategories.getChildAt(pos);
			TextView selectedTvContent = (TextView) selectedView.getTag();
			selectedTvContent.setTextColor(getResources().getColor(
					R.color.category_background_over_color));
			mCurrentCategoryIndex = pos;
			resetCurrentSubCategories();
		}

	}
	
	private void setInvoiceFilterItemSelected(int pos) {
		if  (mCurrentInvoiceFilterIndex != pos) {
			// update status of selected view.
			if (mCurrentInvoiceFilterIndex >= 0) {
				View oldSelectedView = mLlCategories
						.getChildAt(mCurrentInvoiceFilterIndex);
				TextView oldTvContent = (TextView) oldSelectedView.getTag();

				oldTvContent.setTextColor(getResources().getColor(
						R.color.black_color));
			}
			View selectedView = mLlCategories.getChildAt(pos);
			TextView selectedTvContent = (TextView) selectedView.getTag();
			selectedTvContent.setTextColor(getResources().getColor(
					R.color.category_background_over_color));
			mCurrentInvoiceFilterIndex = pos;
		}
		mInvoiceAdapter.setInvoiceSelectedIndex(0);
	}

	/**
	 * set position of selected item subcategory.
	 * 
	 * @param pos
	 *            the position that is selected.
	 */
	private void setSubCategoryItemSelected(int pos) {
		if (mLlSubCategories.getChildCount() == 0) {
			return;
		}
		if (mCurrentSubCategoryIndex != pos) {
			// update status of selected view.
			if (mCurrentSubCategoryIndex >= 0) {
				TextView oldSelectedView = (TextView) mLlSubCategories
						.getChildAt(mCurrentSubCategoryIndex);
				oldSelectedView.setBackgroundColor(getResources().getColor(
						R.color.trasparent_color));
			}
			TextView selectedView = (TextView) mLlSubCategories.getChildAt(pos);
			selectedView.setBackgroundColor(getResources().getColor(
					R.color.subcategory_background_over_color));
			mCurrentSubCategoryIndex = pos;
		}
		resetCurrentFoods();
	}

	/**
	 * reset list of data after select an item of category.
	 */
	private void resetCurrentSubCategories() {
		initSubCategoryLayout();
		mCurrentSubCategoryIndex = Constants.INVALID_VALUE;
		setSubCategoryItemSelected(0);

	}

	/** reset list of foods after select an item of subcategory. */
	private void resetCurrentFoods() {
		// reset list of foods.
		synchronized (mCurrentFoods) {
			mCurrentFoods.clear();
			ArrayList<SubCategory> subCategories = mCategories.get(
					mCurrentCategoryIndex).getSubCategories();
			if (subCategories.size() > 0) {
				mCurrentFoods.addAll(subCategories
						.get(mCurrentSubCategoryIndex).getFoods());

			}
		}
		if (mFoodAdapter != null) {
			mFoodAdapter.notifyDataSetChanged();
		}
		if (mCacheManager != null) {
			mCacheManager.reset();
		}
	}

	@Override
	public void onClick(View v) {
		if (v == null) {
			return;
		}
		
		switch (v.getId()) {
		case R.id.main_bt_discount:
			this.considerDiscount();
			break;
		case R.id.main_bt_language:
			showPopupMenuLanguage(v);
			break;
		case R.id.main_bt_payment:
			this.performPayment();
			break;
		case R.id.main_bt_printorder:
			this.printOrder();
			break;
		case R.id.user_iv_icon:
			showPopupUser(v);
			// // start LoginActivity and finish this activity.
			// Intent intent = new Intent(getApplicationContext(),
			// LoginActivity.class);
			// startActivity(intent);
			// finish();
			break;
		case R.id.main_bt_order:
			if (mOrderAdapter != null) {
				Order currentOrder = mOrders.get(mCurrentTableIndex);
				mOrderAdapter.setCurrentOrder(currentOrder);
			}
			
			this.tabHost.setCurrentTab(0);
			this.mBtOrder.setSelected(true);
			this.mBtInvoice.setSelected(false);
			this.mBtTableJoinSplit.setSelected(false);
			this.initCategoryLayout();
			break;
		case R.id.main_bt_invoice:
			this.tabHost.setCurrentTab(1);
			this.mBtOrder.setSelected(false);
			this.mBtInvoice.setSelected(true);
			this.mBtTableJoinSplit.setSelected(false);
			this.initInvoiceFilterLayout();
			break;
		case R.id.main_bt_table_join_split:
			if (m1stOrderAdapter != null) {
				Order currentOrder = mOrders.get(m1stCurrentTableIndex);
				m1stOrderAdapter.setCurrentInvoice(currentOrder);
			}
			
			if (m2ndOrderAdapter != null) {
				Order currentOrder = mOrders.get(m2ndCurrentTableIndex);
				m2ndOrderAdapter.setCurrentInvoice(currentOrder);
			}
			
			this.tabHost.setCurrentTab(2);
			this.mBtOrder.setSelected(false);
			this.mBtInvoice.setSelected(false);
			this.mBtTableJoinSplit.setSelected(true);
			this.initSplitJoinTableLayout();
			break;
		default:
			break;
		}
	}

	private void performPayment() {
		if (mOrders == null || mOrders.size() < mCurrentTableIndex) {
			return;
		}
		
		double totalMoneyWillPay = mOrders.get(mCurrentTableIndex)
				.getTotalMoneyWillPay();
		Order order = null;
		if (mOrders != null && mOrders.size() > 0) {
			order = mOrders.get(mCurrentTableIndex);
		}
		
		if (mPaymentDialog == null) {
			mPaymentDialog = new PaymentDialog(this, totalMoneyWillPay,
					order);

			mPaymentDialog.setOnDismissListener(new OnDismissListener() {

				@Override
				public void onDismiss(DialogInterface dialog) {
					// save this order to order database.
					Log.d(TAG, " mOrders.size() = " +   mOrders.size());
					Log.d(TAG, "mCurrentTableIndex = " + mCurrentTableIndex);
					Log.d(TAG, "mPaymentDialog.isPrintBill() = " + mPaymentDialog.isPrintBill());

					if (MainActivity.this.mPaymentDialog.isPrintBill())
					{
						Order invoice = mOrders.get(mCurrentTableIndex);
						MainActivity.this.addInvoice(invoice);
						MainActivity.this.sendInvocieToServer(invoice);
						if (MainActivity.this.isNotFinishSendToServer(MainActivity.this.mAllInvoices)) {
							MainActivity.this.sendInvociesToServer(MainActivity.this.mAllInvoices);
						}
					}

					if (mOrders == null || mOrders.size() <= mCurrentTableIndex
							|| mPaymentDialog.isPrintBill() == false) {
						return;
					}
					
					Order order = mOrders.get(mCurrentTableIndex);
					//set table id.
					order.setTableID(mTables.get(mCurrentTableIndex).getId());
					order.setTable(mTables.get(mCurrentTableIndex).getName());
					order.setAreaID(mTables.get(mCurrentTableIndex).getAreaID());
					Log.d("MainActivity", "====insert AreaName===" +  mTables.get(mCurrentTableIndex).getAreaName() );
					order.setAreaName(mTables.get(mCurrentTableIndex).getAreaName());
					//set datetime
					Date date = new Date();
					Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
					String strDate = formatter.format(date);
					order.setEnd(strDate);
					savePrintedOrderToDatabase(order);
					// create new order for this position.
					Order newOrder = new Order();

					newOrder.setId(PrefUtils.getInt(
							getApplicationContext(), Constants.PREF_ORDER_ID, 0) + 1);
					PrefUtils.writeInt(getApplicationContext(),
							Constants.PREF_ORDER_ID, newOrder.getId());

					// set table id.
					newOrder.setTableID(mTables.get(mCurrentTableIndex).getId());
					newOrder.setTable(mTables.get(mCurrentTableIndex).getName());
					newOrder.setAreaID(mTables.get(mCurrentTableIndex).getAreaID());
					newOrder.setAreaName(mTables.get(mCurrentTableIndex).getAreaName());
					mOrders.set(mCurrentTableIndex, newOrder);
					if (mOrderAdapter != null) {
						mOrderAdapter.setCurrentOrder(newOrder);
					}
					
					if (mFoodAdapter != null) {
						mFoodAdapter.setCurrentOrder(newOrder);
						mFoodAdapter.notifyDataSetChanged();
					}
					
					updateTotalMoney();
				}
			});
		} else {
			mPaymentDialog.reset(order, totalMoneyWillPay);
		}

		mPaymentDialog.show();
	}
	
	private void printOrder() {
		if (mOrders == null || mOrders.size() < mCurrentTableIndex) {
			return;
		}
		
		Order printOrder = null;
		if (mOrders != null && mOrders.size() > 0) {
			printOrder = mOrders.get(mCurrentTableIndex);
		}
		
		if (printOrder == null) {		
			// Show dialog "no order to print".
			Dialog mDialog = new Dialog(this);
			mDialog.setTitle("No order to print");
			mDialog.show();
		}

		ESCPSample2 sample = new ESCPSample2(printOrder);
		try {
			sample.printOrder();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void considerDiscount() {
		if (getDiscountDialog() == null) {
			setDiscountDialog(new DiscountDialog(this));
		} else {
			getDiscountDialog().resetDialog();
		}
		
		getDiscountDialog().setOnDismissListener(new OnDismissListener() {

			@Override
			public void onDismiss(DialogInterface dialog) {
				Discount discount = getDiscountDialog().getDiscount();
				if (discount != null && mOrders != null
						&& mOrders.size() > mCurrentTableIndex) {
					mOrders.get(mCurrentTableIndex).setDiscount(discount);
					updateTotalMoney();
				}
			}
		});
		
		getDiscountDialog().show();
	}
	
	private void addInvoice(Order order) {
		if (order == null) {
			return;
		}
		
		// Get today's date			 
		Date date = new Date();
		Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String strDate = formatter.format(date);

		Order newOrder = new Order(order);
		newOrder.setEnd(strDate);
		
		this.mAllInvoices.add(newOrder);
		this.mInvoices.add(newOrder);
		if (mInvoiceAdapter != null) {
			mInvoiceAdapter.notifyDataSetChanged();
		}
		
		this.mTotalMoneyOfInvoices += order.getTotalMoneyWillPay();
		this.mTvTotalMoneyOfInvoices.setText(CommonUtils.convertMoneyToString(this.mTotalMoneyOfInvoices));
		if (this.mInvoices.size() == 1) {
			this.mCurrentInvoiceSelectedIndex = 0;
			this.initInvoiceDetailLayout();
			if (mInvoiceDetailAdapter != null) {
				mInvoiceDetailAdapter.notifyDataSetChanged();
			}
		}
	}
	
	private void showPopupUser(View v) {
		final PopupMenu popupMenu = new PopupMenu(this, v);
		int menuRes = R.menu.menu_user_vn;
		if (MyCoffeeApplication.mLanguage == Constants.LANGUAGE_EN) {
			menuRes = R.menu.menu_user_en;
		} else if (MyCoffeeApplication.mLanguage == Constants.LANGUAGE_DE) {
			menuRes = R.menu.menu_user_de;
		}
		popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu());
		popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

			@Override
			public boolean onMenuItemClick(MenuItem item) {
				switch (item.getItemId()) {
				case R.id.menu_user_item_homepage:

					break;
				case R.id.menu_user_item_personalinfo:

					break;
				case R.id.menu_user_item_logout:
					// start LoginActivity and finish this activity.
					Intent intent = new Intent(getApplicationContext(),
							LoginActivity.class);
					startActivity(intent);
					finish();
					break;
				default:

				}
				popupMenu.dismiss();
				return true;
			}
		});
		popupMenu.show();

	}

	/**
	 * save the order that has been payed to database.
	 * 
	 * @param order
	 */
	public void savePrintedOrderToDatabase(Order order) {
		ArrayList<Order> orders = new ArrayList<Order>();
		orders.add(order);
		OrderEditTask task = new OrderEditTask(getApplicationContext(), null,
				false, orders);
		task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

	}

	/**
	 * show popup menu and process changing language.
	 */
	private void showPopupMenuLanguage(View v) {
		final PopupMenu popupMenu = new PopupMenu(this, v);
		int menuRes = R.menu.menu_language_vn;
		if (MyCoffeeApplication.mLanguage == Constants.LANGUAGE_EN) {
			menuRes = R.menu.menu_language_en;
		} else if (MyCoffeeApplication.mLanguage == Constants.LANGUAGE_DE) {
			menuRes = R.menu.menu_language_de;
		}
		popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu());
		popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

			@Override
			public boolean onMenuItemClick(MenuItem item) {
				int newLanguage = 0;
				switch (item.getItemId()) {
				case R.id.menu_language_item_vn:
					newLanguage = Constants.LANGUAGE_VN;
					break;
				case R.id.menu_language_item_en:
					newLanguage = Constants.LANGUAGE_EN;
					break;
				case R.id.menu_language_item_de:
					newLanguage = Constants.LANGUAGE_DE;
					break;
				default:

				}
				if (newLanguage != MyCoffeeApplication.mLanguage) {
					// display new language.
					MyCoffeeApplication.mLanguage = newLanguage;
					updateLanguage();
				}
				popupMenu.dismiss();
				return true;
			}
		});
		popupMenu.show();

	}

	/**
	 * receive action when user click on buttons to edit order: delete, add,
	 * remove.
	 * 
	 * @param v
	 */
	public void onOrderEditClick(View v) {
		if (v == null || mOrders == null) {
			return;
		}
		switch (v.getId()) {
		case R.id.order_item_iv_delete:
			// delete this order.
			int pos = (Integer) v.getTag();
			deleteOrderDetail(pos);
			break;
		case R.id.order_item_iv_add:

			increaseOrder();
			break;
		case R.id.order_item_iv_remove:
			decreaseOrder();
			break;
		case R.id.order_footer_iv_delete_discount:
			// delete discount
			if (mOrders == null || mOrders.size() <= mCurrentTableIndex) {
				break;
			}
			mOrders.get(mCurrentTableIndex).setDiscount(null);
			updateTotalMoney();
			return;
		default:
			break;
		}
		// update list of order.
		if (mOrderAdapter != null) {
			mOrderAdapter.notifyDataSetChanged();
		}
		// update list of food.
		if (mFoodAdapter != null) {
			mFoodAdapter.notifyDataSetChanged();
		}
		// update total money.
		// mTvTotalMoney.setText("" +
		// mOrders.get(mCurrentTableIndex).getTotal());
		updateTotalMoney();
	}

	private void decreaseOrder() {
		if (mOrders == null || mCurrentTableIndex < 0
				|| mCurrentTableIndex >= mOrders.size()) {
			return;
		}
		Order currentOrder = mOrders.get(mCurrentTableIndex);
		int oldNumberOrderDetails = currentOrder.getOrdersDetails().size();
		currentOrder.decreaseOrderDetail(mCurrentOrderDetailSelectedIndex);
		if (currentOrder.getOrdersDetails().size() < oldNumberOrderDetails) {
			// the order detail has been removed from order.
			mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
			if (mOrderAdapter != null) {
				mOrderAdapter
						.setOrderDetailSelectedIndex(mCurrentOrderDetailSelectedIndex);
			}
		}
	}

	private void increaseOrder() {
		if (mOrders == null || mCurrentTableIndex < 0
				|| mCurrentTableIndex >= mOrders.size()) {
			return;
		}
		Order currentOrder = mOrders.get(mCurrentTableIndex);
		currentOrder.increaseOrderDetail(mCurrentOrderDetailSelectedIndex);

	}

	/**
	 * delete an order detail from an order.
	 * 
	 * @param pos
	 */
	private void deleteOrderDetail(int pos) {
		Order order = mOrders.get(mCurrentCategoryIndex);
		ArrayList<OrdersDetail> ordersDetails = order.getOrdersDetails();
		if (pos >= 0 && pos < ordersDetails.size()) {
			OrdersDetail ordersDetail = ordersDetails.get(pos);
			ordersDetails.remove(pos);
			double total = order.getTotal() - ordersDetail.getAmount()
					* ordersDetail.getFood().getPrice();
			order.setTotal(total);
			if (pos <= mCurrentOrderDetailSelectedIndex) {
				if (pos == mCurrentOrderDetailSelectedIndex) {
					mCurrentOrderDetailSelectedIndex = Constants.INVALID_VALUE;
				} else if (mCurrentOrderDetailSelectedIndex > pos) {
					mCurrentOrderDetailSelectedIndex--;
				}
				if (mOrderAdapter != null) {
					mOrderAdapter
							.setOrderDetailSelectedIndex(mCurrentOrderDetailSelectedIndex);
				}
			}
		}
	}

	// called by button list item to link to list item activity
	public void onClickSetting(View v) {
		final Dialog dlgPass = new Dialog(this);
		dlgPass.setContentView(R.layout.password_dialog);
		dlgPass.setTitle(getString(R.string.admin_pass));
		final EditText etPassword = (EditText) dlgPass
				.findViewById(R.id.etAdminPassword);
		final Button btLogin = (Button) dlgPass.findViewById(R.id.btLogin);
		btLogin.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				if (TextUtils
						.equals(PASS_WORD, etPassword.getText().toString())) {
					// start dialog to input password.
					// start dialog to input password.
					Intent intent = new Intent(getApplicationContext(),
							PrinterSettingDialog.class);
					startActivity(intent);
					dlgPass.dismiss();
				}
			}
		});
		dlgPass.show();
	}
	

	// called by button list item to link to list item activity
	public void onClickPrint(View v) {
		if (mOrders != null && mOrders.size() > 0) {
			ESCPSample2 sample = new ESCPSample2(
					mOrders.get(mCurrentTableIndex));
			try {
				sample.sample1();
				showErrorDialog("Print completed");
			} catch (Exception e) {
				showErrorDialog("Error occur");
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			ESCPSample2 sample = new ESCPSample2();
			showErrorDialog("Print completed");
			try {
				sample.sample1();
			} catch (Exception e) {
				showErrorDialog("Error occur");
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * Show Error Dialog
	 * 
	 * @param string
	 */
	private void showErrorDialog(String msg) {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage(msg);
		builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
			}
		});
		builder.show();
	}

	/**
	 * Set up Bluetooth.
	 */
	private void bluetoothSetup() {
		// Initialize
		clearBtDevData();
		bp = BluetoothPort.getInstance();
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		if (mBluetoothAdapter == null) {
			// Device does not support Bluetooth
			return;
		}
		if (!mBluetoothAdapter.isEnabled()) {
			Intent enableBtIntent = new Intent(
					BluetoothAdapter.ACTION_REQUEST_ENABLE);

			startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
		}
	}

	private void clearBtDevData() {
		setRemoteDevices(new Vector<BluetoothDevice>());
	}

	// Bluetooth Connection method.
	private void btConn(final BluetoothDevice btDev) throws IOException {
		new connTask().execute(btDev);
	}

	/** ======================================================================= */
	public class connTask extends AsyncTask<BluetoothDevice, Void, Integer> {
		private final ProgressDialog dialog = new ProgressDialog(
				MainActivity.this);

		@Override
		protected void onPreExecute() {
			dialog.setTitle("Bluetooth");
			dialog.setMessage("Connecting");
			dialog.show();
			super.onPreExecute();
		}

		@Override
		protected Integer doInBackground(BluetoothDevice... params) {
			Integer retVal = null;
			try {
				bp.connect(params[0]);
				retVal = Integer.valueOf(0);
			} catch (IOException e) {
				retVal =  Integer.valueOf(-1);
			}
			return retVal;
		}

		@Override
		protected void onPostExecute(Integer result) {
			if (result.intValue() == 0) {
				RequestHandler rh = new RequestHandler();
				hThread = new Thread(rh);
				hThread.start();
				connected = true;
			}
			if (dialog.isShowing()) {
				String cmsg;
				dialog.dismiss();
				if (connected) {
					// Save to config as default device
					SharedPreferences settings = getSharedPreferences(
							BT_DEVICE_ADDRESS, 0);
					SharedPreferences.Editor editor = settings.edit();
					editor.putString("deviceAddress", currentDeviceAddress);

					// Commit the edits!
					editor.commit();

					cmsg = "Bluetooth Connected";
					showErrorDialog(cmsg);
					// Toast toast = Toast.makeText(PrinterSettingDialog.this,
					// cmsg,
					// Toast.LENGTH_LONG);
					// toast.show();
					// finish();
				} else {
					cmsg = "Bluetooth Not Connected.";
					AlertView.showError(cmsg, MainActivity.this);
					// finish();
				}
			}
			super.onPostExecute(result);
		}
	}

	/**
	 * Bluetooth connection status.
	 * 
	 * @return connected - boolean
	 */
	public static boolean isConnected() {
		return connected;
	}

	public DiscountDialog getDiscountDialog() {
		return mDiscountDialog;
	}

	public void setDiscountDialog(DiscountDialog mDiscountDialog) {
		this.mDiscountDialog = mDiscountDialog;
	}

	public ProgressDialog getDialog() {
		return dialog;
	}

	public void setDialog(ProgressDialog dialog) {
		this.dialog = dialog;
	}

	public Vector<BluetoothDevice> getRemoteDevices() {
		return remoteDevices;
	}

	public void setRemoteDevices(Vector<BluetoothDevice> remoteDevices) {
		this.remoteDevices = remoteDevices;
	}

	public LinearLayout getLlOrderFooterTotal() {
		return mLlOrderFooterTotal;
	}

	public void setLlOrderFooterTotal(LinearLayout mLlOrderFooterTotal) {
		this.mLlOrderFooterTotal = mLlOrderFooterTotal;
	}

	public TextView getTvOrderFooterDiscountTitle() {
		return mTvOrderFooterDiscountTitle;
	}

	public void setTvOrderFooterDiscountTitle(
			TextView mTvOrderFooterDiscountTitle) {
		this.mTvOrderFooterDiscountTitle = mTvOrderFooterDiscountTitle;
	}

	public TextView getTvOrderFooterTotalTitle() {
		return mTvOrderFooterTotalTitle;
	}

	public void setTvOrderFooterTotalTitle(TextView mTvOrderFooterTotalTitle) {
		this.mTvOrderFooterTotalTitle = mTvOrderFooterTotalTitle;
	}

	private boolean isNotFinishSendToServer(ArrayList<Order> invoices) {
		for (Order invoice : invoices) {
			if (invoice.getSent2Server() == false) {
				return true;
			}
		}
		
		return false;
	}

	private void sendInvociesToServer(ArrayList<Order> invoices) {
		final ArrayList<Order> sentList = new ArrayList<Order>();
		for (Order invoice : invoices) {
			sentList.add(invoice);
		}
		
		Gson gson = new Gson();
		String sendMessage = gson.toJson(sentList);
		UploadInvoiceTask uploadTask = new UploadInvoiceTask() {
			@Override
		    protected void onPostExecute(Boolean result) {
				for (Order invoice : sentList) {
				    invoice.setSent2Server(result);
				}
		    }
		};
		
		uploadTask.execute(sendMessage);
	}

	private void sendInvocieToServer(final Order invoice) {
		Gson gson = new Gson();
		String sendMessage = gson.toJson(invoice);
		UploadInvoiceTask uploadTask = new UploadInvoiceTask() {
			@Override
		    protected void onPostExecute(Boolean result) {
				invoice.setSent2Server(result);
		    }
		};
		
		uploadTask.execute(sendMessage);
	}
	
	private boolean isOverDay(String end) {
		try {
			long day = 24 * 60 * 60 * 1000;
			Date date = new Date();
			Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date temp = (Date) formatter.parseObject(end);
			return date.getTime() / day >= temp.getTime() / day;
		} catch (Exception ex) {
			return false;
		}
	}
	
	private void filterInvoiceByDay() {
		this.mInvoices = new ArrayList<Order>();
		
		for (Order invoice : this.mAllInvoices) {
			if (this.isOverDay(invoice.getEnd()) == false) {
				this.mInvoices.add(invoice);
			}
		}

		if (this.mInvoiceAdapter != null) {
			this.mInvoiceAdapter = new InvoiceAdapter(getBaseContext(), this.mInvoices);
			this.mLvInvoices.setAdapter(this.mInvoiceAdapter);
		}

		if (this.mInvoiceDetailAdapter != null) {
			if (this.mInvoices.size() != 0) {
			    this.mInvoiceDetailAdapter.setCurrentInvoice(this.mInvoices.get(0));
			}
		}
	}
	
	private boolean isOver7Day(String end) {
		try {
			long day = 24 * 60 * 60 * 1000;
			Date date = new Date();
			Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Date temp = (Date) formatter.parseObject(end);
			return date.getTime() / day - temp.getTime() / day >= 7;
		} catch (Exception ex) {
			return false;
		}
	}
	
	private void filterInvoiceByWeek() {
		this.mInvoices = new ArrayList<Order>();
		
		for (Order invoice : this.mAllInvoices) {
			if (this.isOver7Day(invoice.getEnd()) == false) {
				this.mInvoices.add(invoice);
			}
		}

		if (this.mInvoiceAdapter != null) {
			this.mInvoiceAdapter = new InvoiceAdapter(getBaseContext(), this.mInvoices);
			this.mLvInvoices.setAdapter(this.mInvoiceAdapter);
		}

		if (this.mInvoiceDetailAdapter != null) {
			if (this.mInvoices.size() != 0) {
			    this.mInvoiceDetailAdapter.setCurrentInvoice(this.mInvoices.get(0));
			}
		}
	}
}